package com.southgis.ibase.sql.func;

import java.util.List;

import org.hibernate.dialect.Dialect;

/**
 * 不同数据库独有的SQL片段特殊语法处理类，除hibernate定义的dialect（定义数据类型）、com.alibaba.druid（定义sql分析、分页处理）之外的需求。<br>
 * dialect使用：<br>
 * 获取注册的函数：getFunctions<br>
 * 获取某种类型的定义：getTypeName<br>
 * 当前时间的语句（不需要额外加括号）：getCurrentTimestampSQLFunctionName<br>
 *   如："update job_base set accdate="+dialect.getCurrentTimestampSQLFunctionName()+" where jid='2020031800493'"<br>
 * 值转换函数：cast<br>
 * 转小写函数（仅名字，需要加括号）：getLowercaseFunction<br>
 * <br>
 * 删除表语句：getDropTableString<br>
 * 添加字段语法：getAddColumnString/getAddColumnSuffixString<br>
 * <p>
 * druid使用：<br>
 * 生成分页语句，使用：com.alibaba.druid.sql.PagerUtils<br>
 * 分析SQL语句，使用：com.alibaba.druid.sql.SQLUtils
 * </p>
 * <p>接口方法注释，请参看{@link com.southgis.ibase.utils.dao.DatabaseFunc}同名方法</p>
 * @author dennis
 *
 */
public interface IExclusiveDatabaseFunc
{
	/**
	 * 设置关联的方言类，主要用于其他方法的处理
	 * @param dialect 方言
	 * @param dbType 数据库类型名，与DataSourceTypeEnum保持一致
	 */
	void setDialect(Dialect dialect,String dbType);

	//README 类型定义
	/**
	 * @see DatabaseFunc#charType
	 * @param len
	 * @return
	 */
	String charType(int len);

	/**
	 * @see DatabaseFunc#binaryType
	 * @param len
	 * @return
	 */
	String binaryType(int len);

	/**
	 * @see DatabaseFunc#datetimeType
	 * @return
	 */
	String datetimeType();

	/**
	 * @see DatabaseFunc#doubleType
	 * @return
	 */
	String doubleType();

	/**
	 * @see DatabaseFunc#decimalType
	 * @param len
	 * @param scale
	 * @return
	 */
	String decimalType(int len,int scale);

	/**
	 * 生成整数类型
	 * @param width 目前支持：1=字节型byte、2=短整数smallint、4=整数int、8=大整数bigint、16=巨大整数decimal(32,0)
	 * @return
	 * @see DatabaseFunc#intType
	 */
	String intType(int width);

	/**
	 * 生成字符串非空判断条件。
	 * 如有''值的：(fn is not null and fn<>'') <br>
	 * 没有''值的(oracle)：fn is not null
	 * @see DatabaseFunc#notEmptyCharWhere
	 * @param fieldName
	 * @return
	 */
	String notEmptyCharWhere(String fieldName);

	/**
	 * @see DatabaseFunc#emptyCharWhere
	 * @param fieldName
	 * @return
	 */
	String emptyCharWhere(String fieldName);

	//README 函数调用，或值转换
	/**
	 * @see DatabaseFunc#concatChar
	 * @param charVals
	 * @return
	 */
	String concatChar(String... charVals);
	
	
	/**
	 * @see DatabaseFunc#concatChar
	 * @param charVal
	 * @param start 基于0开始的开始位置（包含）
	 * @param end 基于0开始的结束位置（不包含）
	 * @return
	 */
	String subChar(String charVal, int start, int end);

	/**
	 * @see DatabaseFunc#getCharToDateInvoke
	 * @param charVal
	 * @param fmt
	 * @return
	 */
	String getCharToDateInvoke(String charVal, int fmt);

	/**
	 * @see DatabaseFunc#getYearInvoke
	 * @param dateVal
	 * @return
	 */
	String getYearInvoke(String dateVal);

	/**
	 * 得到SQL日期常量值的表示方法，如：<br>
	 * String dateVal=func.getDateConst("2020-12-31");<br>
	 * 一般sql类型，返回：“date'2020-12-31'”<br>
	 * mssql，返回：“'2020-12-31'”
	 * @param fmtVal 系统标准日期格式的sql常量字符串（注，也可省略单引号，因为已明确此参数是常量，如果省略，内部会自动添加）
	 * @return sql日期常量值的表示
	 */
	String getDateConst(String fmtVal);
	
	/**
	 * @see DatabaseFunc#getCastInvoke
	 * @param orgVal
	 * @param targetType
	 * @param length
	 * @param scale
	 * @return
	 */
	String getCastInvoke(String orgVal, int targetType,int length, int scale);
	
	/**
	 * @see DatabaseFunc#getLowerInvoke
	 * @param orgVal
	 * @return
	 */
	String getLowerInvoke(String orgVal);
	
	/**
	 * @see DatabaseFunc#getUpperInvoke
	 * @param orgVal
	 * @return
	 */
	String getUpperInvoke(String orgVal);
	
	/**
	 * @see DatabaseFunc#getIfnullInvoke
	 * @param orgVal
	 * @param other
	 * @return
	 */
	String getIfnullInvoke(String orgVal, String other);
	
	/**
	 * @see DatabaseFunc#getNowInvoke
	 * @return
	 */
	String getNowInvoke();

	//README SQL处理
	/**
	 * 在sql语句上添加分页条件
	 * @see DatabaseFunc#pageSql
	 * @param sql
	 * @param offset
	 * @param pageSize
	 * @return
	 */
	String pageSql(String sql, int offset, int pageSize);

	/**
	 * 转为获取计数的sql语句
	 * @see DatabaseFunc#countSql
	 * @param sql
	 * @return
	 */
	String countSql(String sql);

	//README 表元数据操作语句
	/**
	 * @see DatabaseFunc#sqlOfTableCount
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfTableCount(String tableName, String schema);

	/**
	 * @see DatabaseFunc#sqlOfListTable
	 * @param name
	 * @param type
	 * @param schema
	 * @return
	 */
	String sqlOfListTable(String name, TableTypeEnum type, String schema);

	/**
	 * @see DatabaseFunc#sqlOfListColumns
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfListColumns(String tableName, String schema);

	/**
	 * @see DatabaseFunc#sqlOfListConstraint
	 * @param type
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfListConstraint(ConstraintTypeEnum type, String tableName,String schema);

	/**创建表
	 * @see DatabaseFunc#sqlOfCreateTable
	 * @param tableName
	 * @param comment
	 * @param colDef
	 * @param schema
	 * @return
	 */
	List<String> sqlOfCreateTable(String tableName, String comment, List<ColumnDefine> colDef, String schema);
	
	/**修改描述
	 * @see DatabaseFunc#sqlOfModifyTableComment
	 * @param comment
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfModifyTableComment(String comment,String tableName,String schema);
	
	/**添加字段
	 * @see DatabaseFunc#sqlOfAddColumn
	 * @param colDef
	 * @param tableName
	 * @param schema
	 * @return
	 */
	List<String> sqlOfAddColumn(ColumnDefine colDef,String tableName, String schema);

	/**修改字段定义
	 * @see DatabaseFunc#sqlOfModifyColumn
	 * @param colDef
	 * @param tableName
	 * @param schema
	 * @return
	 */
	List<String> sqlOfModifyColumn(ModifyColumnDefine colDef,String tableName, String schema);
	
	/**删除字段
	 * @see DatabaseFunc#sqlOfDropColumn
	 * @param colName
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfDropColumn(String colName, String tableName, String schema);

	/**添加主键约束，大部分为：
	 * ALTER TABLE {table} ADD CONSTRAINT {constraint} PRIMARY KEY({fields})
	 * @see DatabaseFunc#sqlOfAddPrimaryKey
	 * @param keyName
	 * @param colName
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfAddPrimaryKey(String keyName, String colName, String tableName, String schema);
	
	/**删除主键约束
	 * @see DatabaseFunc#sqlOfDropPrimaryKey
	 * @param keyName
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfDropPrimaryKey(String keyName, String tableName, String schema);

	/**
	 * 添加唯一约束。标准语句：
	 * ALTER TABLE {table} ADD CONSTRAINT {constraint} UNIQUE({fields})
	 * @param keyName
	 * @param colName
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfAddUniqueKey(String keyName, String colName, String tableName, String schema);

	/**删除唯一约束
	 * @see DatabaseFunc#sqlOfDropUniqueKey
	 * @param keyName
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfDropUniqueKey(String keyName, String tableName, String schema);

	/**删除外键（不建议添加外键），大部分为：
	 * ALTER TABLE {table} ADD CONSTRAINT {constraint} FOREIGN KEY({field}) REFERENCES {reftable}({reffield})
	 * @see DatabaseFunc#sqlOfDropForeignKey
	 * @param keyName
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfDropForeignKey(String keyName, String tableName, String schema);

	//(oracle/达梦)alter table {table} disable constraint {constraint}
	//alter table {table} enable constraint {constraint}
	//(mysql)set foreign_key_checks=0
	//set foreign_key_checks=0
	//(sqlserver)alter table {table} nocheck constraint {constraint}
	//alter table {table} check constraint {constraint}
	//(postgre/金仓) alter table {table} ALTER CONSTRAINT {constraint} DEFERRABLE INITIALLY DEFERRED
	//alter table {table} ALTER CONSTRAINT {constraint} NOT DEFERRABLE
	/**禁用/启用外键
	 * @see DatabaseFunc#sqlOfEnableForeignKey
	 * @param keyName
	 * @param enabled
	 * @param tableName
	 * @param schema
	 * @return
	 */
	String sqlOfEnableForeignKey(String keyName, Boolean enabled, String tableName, String schema);

	//README 辅助类
	/**
	 * 常用返回字段别名常量类
	 * <p>
	 *   因SQL执行后返回字段需要在外部使用,
	 *   以及与{@link DatabaseFunc}关系密切,所以使用内部类维护
	 * </p>
	 */
	final class ResultColumns {

		private ResultColumns() {}

		/** 表名 */
		public static final String TABLE_NAME = "TABLE_NAME";
		/** 表注释 */
		public static final String TABLE_COMMENT = "TABLE_COMMENT";
		/** 表类型，返回值1=table,2=view */
		public static final String TABLE_TYPE = "TABLE_TYPE";

		/** 字段名 */
		public static final String COLUMN_NAME = "COLUMN_NAME";
		/** 字段注释 */
		public static final String COLUMN_COMMENT = "COLUMN_COMMENT";
		/** 字段值是否可空 */
		public static final String COLUMN_NULLABLE = "COLUMN_NULLABLE";
		/** 数据类型 */
		public static final String DATA_TYPE = "DATA_TYPE";
		/** 数据定义长度 */
		public static final String DATA_LENGTH = "DATA_LENGTH";
		/** 数据保留小数位 */
		public static final String DATA_SCALE = "DATA_SCALE";
		/** 数据长度定义，某些数据库，无法直接拆分DATA_LENGTH和DATA_SCALE，在此字段返回定义长度信息，格式：(length,scale)。
		 * 当 DATA_LENGTH和DATA_SCALE值都为-1时，通过此字段值分析长度定义
		 */
		public static final String DATA_DEFINE = "DATA_DEFINE";

		/** 约束名 */
		public static final String CONS_NAME = "CONS_NAME";
		/** 约束类型 */
		public static final String CONS_TYPE = "CONS_TYPE";

		/** 元数据记录总数 */
		public static final String COUNT = "COUNT";
	}

	/**
	 * 对表名的查询方式（按位组合）：0不设条件，1表like、2视图like，3表和视图like
	 * 0x101表相等，0x102视图相等，0x103表和视图相等
	 */
	enum TableTypeEnum {

		/** 0 不设类型条件，表名以like查询 */
		UNCONDITIONAL(0),

		/** 1 仅表类型，且表名like查询 */
		TABLE(1),

		/** 2 仅视图类型，且视图名like查询 */
		VIEW(2),

		/** 3表和视图类型，且名称like查询 */
		TABLE_VIEW(3),

		/** 0x101 仅表类型，且表名相等查询 */
		TABLE_EQU(0x101),

		/** 0x102仅视图类型，且视图名相等查询 */
		VIEW_EQU(0x102),

		/** 0x103 表和视图类型，且名称相等查询*/
		TABLE_VIEW_EQU(0x103),

		;

		/**
		 * 表类型
		 */
		private final int type;

		public int getType() {
			return type;
		}

		TableTypeEnum(int type) {
			this.type = type;
		}
	}


	/**
	 * 约束类型（按位组合）：0不设条件，1主键、2唯一、4外键，3主键和唯一，5主键和外键，6唯一和外键，7主键和唯一及外键
	 */
	enum ConstraintTypeEnum {

		/** 0不设条件 */
		UNCONDITIONAL(0),

		/** 1主键 */
		PRIMARY(1),

		/** 2唯一 */
		UNIQUE(2),

		/** 3主键和唯一 */
		PRIMARY_UNIQUE(3),

		/** 4外键 */
		FOREIGN(4),

		/** 5主键和外键 */
		PRIMARY_FOREIGN(5),

		/** 6唯一和外键 */
		UNIQUE_FOREIGN(6),

		/** 7主键和唯一及外键 */
		PRIMARY_UNIQUE_FOREIGN(7),

		/** 所有需要的约束类型 */
		ALL(0x7FFFFFFF),
		;

		/**
		 * 约束类型
		 */
		private final int type;

		public int getType() {
			return type;
		}

		ConstraintTypeEnum(int type) {
			this.type = type;
		}
	}
}
